/********************************************************************************************************************************
 * 《C ++ Primer》第五版中文版，读书笔记：按照书中的的示例源码和每一个小章节的课后习题，自己动手写代码实现，作为联系和测试。
 * Date: 2024-04-01 17:53
 * Author: dimon.chen 
 * EMali: 1181302388@qq.com 
 * 
 * 章节: 第三章 字符串，向量和数组
 *       3.4 迭代器介绍
 * 
 ********************************************************************************************************************************/


#include <iostream>
#include <string>
#include <vector>
#include <cctype>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;


// string 和 vector 都支持通过下标运算符访问容器中的元素或字符。
// 还存在更通用的一种访问string和vector中元素的方法，就是迭代器
// 除了vector容器之外，标准库还定义了其它容器。标准库定义的容器都支持迭代器操作，但只有少数几种容器才同时支持下标操作符。
// vector支持下标操作符和string一样；string支持迭代器和string一样。



// 类似于指针类型，迭代器也提供对对象的间接访问。
// 就迭代器而言其对象是容器中的元素或string中的字符。
// 使用迭代器可以访问某个元素，迭代器也可以从一个元素移动到另外一个元素


// 迭代器有有效和无效之分，这一点和指针类似，有效的迭代器或者指向某个元素，或者指向容器中尾元素的下一位置；其它所有情况都属于无效
//

// 和指针不一样的是，获取迭代器不是使用取地址符。拥有迭代器的类型也同时拥有返回迭代器的成员。
// 比如，这些类型都有名为 begin 和 end 的成员，其中begin成员返回指向第一个元素的迭代器，
// end成员则负责返回容器中尾元素的下一位置的迭代器

// 通常我们不清楚（不关心）迭代器的准确类型到底是什么
// auto b = v.begin();
// auto e = v.end()

// 上述两个例子使用关键字 auto 定义了迭代器变量 b 和 e

int main(int argc, char *argv[]){

    string s("some thing");         //定义string对象，对象中的元素为"something"字符串的所有字符，空字符除外

    cout << "s=" << s << endl;
    if(s.begin() != s.end())        //确保不为空
    {
        auto it = s.begin();        //auto关键字，auto 为迭代器类型
        *it = toupper(*it);         //对迭代器解引用，得到迭代器所指示元素的引用
                                    //对引用赋值，修改引用所绑定对象的值
    }
    cout << "s=" << s << endl;




    //把第一个单词修改为大写
    for(auto &c : s){
        if(isspace(c))
            break;
        
        c = toupper(c);
    }
    cout << s << endl;



    s = "some thing";
    cout << s << endl;

    // 使用关键字 auto 类型指示符，定义循环控制变量it，it是迭代器变量
    // it初始化为容器中指示容器中第一个元素的迭代器
    // 通过判断迭代器变量it是否与 s.end() 返回值 容器尾元素下一位置的迭代器（尾迭代器）是否相等，来判断是否遍历了容器中的素有元素
    // it++，对迭代器执行递增运算符，迭代器移动到下一个元素
    //
    // 和指针类似，通过解引用可以得到迭代器所指示的元素
    // 迭代器解引用运算符返回值为其指示元素的引用
    // 对引用赋值，结果为对其所绑定对象的赋值
    // 引用非对象，引用时别名

    for(auto it = s.begin(); it != s.end() && !isspace(*it); it++){
        *it = toupper(*it);
    }
    cout << s << endl;


    s = "some thing";
    cout << s << endl;
    for(auto it = s.begin(); it != s.end(); it++){
        *it = toupper(*it);
    }
    cout << s << endl;








    vector<string> text;
    text.push_back("Hello how are you?");
    text.push_back("I am fine, thanks you!");
    text.push_back("how do you do");
    text.push_back("");
    text.push_back("Chapter 2");

    //集引用迭代器可获得迭代器所指的对象
    //C++语言定义的箭头运算符把解引用和访问成员两个操作结合在一起
    //箭头运算符把解引用的结果用来访问成员
    //.运算符
    for(auto it = text.cbegin(); it != text.cend() && !it->empty(); it++)
        cout << *it << endl;


    //我们不清楚（不关心）迭代器的确切类型。只需要迭代器可以从一个元素移动到另一个元素
    //迭代器的类型是有对应类型定义的 iterator
    //begin和end成员函数返回值的类型为 xxx::iterator
    //如果返回的迭代器只用来读不用来写，可以妖气放回一个常量迭代器，类似于常量指针（指向常量的指针）
    //C++语言定义了 cbegin 和 cend 成员函数
    //cbegin和cend 返回值结果类型为 xxxx::const_iterator
    cout << "Test vector<string>" << endl;
    vector<string>::const_iterator it2;
    for(it2 = text.cbegin(); it2 != text.cend(); it2++)
        cout << *it2 << endl;


    return 0;
}